from .models import Message
from django.utils import timezone
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from django.db.models import Q
from personal_manage.models import MyUser
from channels.db import database_sync_to_async
from rest_framework_simplejwt.tokens import AccessToken
from asgiref.sync import sync_to_async
import asyncio
from django.http import JsonResponse
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from channels.layers import get_channel_layer


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def unread_count(request):
    user = request.user
    if not user.is_authenticated:
        return JsonResponse({'error': 'Unauthorized'}, status=401)

    count = Message.objects.filter(Receiver_id_id=user, if_read=0).count()
    return JsonResponse({'unread_count': count},status=200)

# ChatConsumer
class ChatConsumer(AsyncWebsocketConsumer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.authenticated = False  # 添加认证状态标识
        self.AUTH_TIMEOUT = 30      # 添加超时时间
        self.auth_timeout_task = None
        self.room_group_name = None
        self.user = None

    async def connect(self):
        await self.accept()
        self.auth_timeout_task = asyncio.create_task(self.handle_auth_timeout())

    async def disconnect(self, close_code):
        # 离开 WebSocket 群组
        if self.auth_timeout_task and not self.auth_timeout_task.done():
            self.auth_timeout_task.cancel()

        if self.authenticated and self.room_group_name:
            await self.channel_layer.group_discard(
                self.room_group_name,
                self.channel_name
            )
        # 将用户标记为离线
        await self.remove_user_from_online_set(self.user.id)

    async def receive(self, text_data):
        # 接收消息并解析
        text_data_json = json.loads(text_data)
        _type = text_data_json.get('type')
        if not self.authenticated:
            if _type == 'authenticate':
                if self.auth_timeout_task:
                        self.auth_timeout_task.cancel()
                await self.handle_authentication(text_data_json)
            else:
                # 如果第一条消息不是认证消息，关闭连接
                await self.close(code=4001)
        else:
            if _type == 'message':
                msg_data_json = text_data_json.get('message', {})
                await self.handle_message(msg_data_json)

    async def message(self, event):
        message_data = event['message']
        
        # 将消息发送给当前连接的WebSocket客户端
        await self.send(text_data=json.dumps({
            'type': 'message',
            'message': message_data
        }))


    async def handle_authentication(self, data):
        try:

            token = data.get('access')

            if not token:
                await self.close(code=4401)
                return

            access_token = AccessToken(token)
            userid = access_token['user_id']

            self.user = await self.get_user_by_id(userid)
            if not self.user:
                await self.close(code=4401)
                return

            self.authenticated = True
            self.room_group_name = f'chat_{userid}'

            # 将用户标记为在线
            await self.add_user_to_online_set(self.user.id)

            # 认证成功，加入到群组
            await self.channel_layer.group_add(
                self.room_group_name,
                self.channel_name
            )

            # 获取联系人数据
            result = await self.get_contacts(userid)

            # 发送联系人数据
            await self.send(text_data=json.dumps({
                'type': 'contacts',
                'contacts': result
            }))

        except Exception:

            await self.close(code=4401)

    async def handle_message(self, text_data_json):
        sender_id = text_data_json.get('Sender_id')
        receiver_id = text_data_json.get('Receiver_id')
        content = text_data_json.get('content', '')
        msg_type = text_data_json.get('msg_type', 0)  # 默认为文本消息
        timestamp = timezone.now()  # 获取当前时间戳

        if content == ' ':  # 返回历史信息
            msgs = await self.get_message_history(sender_id, receiver_id)
            # 将历史消息发送给客户端
            await self.send(text_data=json.dumps({
                'type': 'history_messages',
                'history_messages': msgs
            }))
        else:
            try:
                sender_obj = await self.get_user_by_id(sender_id)
                receiver_obj =  await self.get_user_by_id(receiver_id)
                is_online  = await self.is_user_online(receiver_id)
                msg = Message(
                    Sender_id=sender_obj,
                    Receiver_id=receiver_obj,
                    content=content,
                    msg_type=msg_type,
                    send_time=timestamp,
                    if_read = 0 if not is_online else 1
                )
                
                await self.save_message(msg)
                
                # 转化 JSON 再发送
                await self.private_message(sender_id, receiver_id, content, msg_type, timestamp)
                
            except Exception:
                await self.send(text_data=json.dumps({
                    'type': 'error',
                    'message': '无效的用户或商品ID'
                }))
                return
            
            

    @sync_to_async
    def get_user_by_id(self, user_id):
        try:
            return MyUser.objects.get(id=user_id)
        except MyUser.DoesNotExist:
            return None
        
        
    @database_sync_to_async
    def get_contacts(self, sender_id):
        all_msgs = Message.objects.filter(
            Q(Sender_id_id=sender_id) | Q(Receiver_id_id=sender_id)
        )

        sender_receivers = all_msgs.filter(Sender_id_id=sender_id).values_list('Receiver_id_id', flat=True)
        receiver_senders = all_msgs.filter(Receiver_id_id=sender_id).values_list('Sender_id_id', flat=True)
        
        # 合并并去重，得到所有联系人ID
        contact_ids = list(set(list(sender_receivers) + list(receiver_senders)))
        
        # 移除当前用户自己
        contact_ids = [cid for cid in contact_ids if cid != sender_id]

        result = []
        for contact_id in contact_ids:
            # 获取联系人用户信息
            contact_user = MyUser.objects.get(id=contact_id)
            
            # 计算未读消息数（从该联系人发送给当前用户的未读消息）
            unread_count = Message.objects.filter(
                Sender_id_id=contact_id,
                Receiver_id_id=sender_id,
                if_read=0
            ).count()
            
            result.append({
                'id': contact_id,
                'username': contact_user.username,
                'avatar': contact_user.avatar,
                'unread_count': unread_count
            })

        return result

    @database_sync_to_async
    def get_message_history(self, sender_id, receiver_id):
        print("sender_id请求历史消息的人:", sender_id)
        Message.objects.filter(
        Sender_id_id=receiver_id,
        Receiver_id_id=sender_id,
        if_read=0
        ).update(if_read=1)

        msgs = Message.objects.filter(
            Q(Sender_id_id=sender_id, Receiver_id_id=receiver_id) |
            Q(Sender_id_id=receiver_id, Receiver_id_id=sender_id)
        ).order_by('send_time')

        result = []
        for msg in msgs:
            result.append({
                'Sender_id': msg.Sender_id.id,
                'Receiver_id': msg.Receiver_id.id,
                'content': msg.content,
                'msg_type': msg.msg_type,
                'send_time': msg.send_time.strftime('%Y-%m-%d %H:%M:%S'),
                'if_read': msg.if_read
            })
        return result

    @database_sync_to_async
    def save_message(self, msg):
        msg.save()

    async def private_message(self, sender_id, receiver_id, content, msg_type, timestamp):
        message_data = {
            'Sender_id': sender_id,
            'Receiver_id': receiver_id,
            'content': content,
            'msg_type': msg_type,
            'send_time': timestamp.strftime('%Y-%m-%d %H:%M:%S'),
            'if_read': 0
        }
        #发给接收者
        receiver_group_name = f'chat_{receiver_id}'
        await self.channel_layer.group_send(
            receiver_group_name,
            {
                'type': 'message',
                'message': message_data
            }
        )
        #发给发送者的前端
        await self.send(text_data=json.dumps({
            'type': 'message',
            'message': message_data
        }))

    async def chat_message(self, event):
        message_data = event['message']
        # 发送消息到 WebSocket 客户端
        await self.send(text_data=json.dumps({
            'type': 'message',
            'message': message_data
        }))
    
    @sync_to_async
    def add_user_to_online_set(self, user_id):
        """添加用户到在线集合"""
        import redis
        r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
        r.sadd("online_users", user_id)
    
    @sync_to_async
    def remove_user_from_online_set(self, user_id):
        """从在线集合移除用户"""
        import redis
        r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
        r.srem("online_users", user_id)
    
    @sync_to_async
    def is_user_online_sync(self, user_id):
        """检查用户是否在线"""
        import redis
        r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
        return r.sismember("online_users", user_id)
    
    async def is_user_online(self, user_id):
        """检查用户是否在线"""
        is_online = await self.is_user_online_sync(user_id)
        return bool(is_online)

    async def handle_auth_timeout(self):
        """处理认证超时"""
        try:
            # 等待设定的超时时间
            await asyncio.sleep(self.AUTH_TIMEOUT)
            # 如果超时后仍未认证，关闭连接
            if not self.authenticated:
                await self.send(text_data=json.dumps({
                    'type': 'error',
                    'message': '认证超时，连接已关闭'
                }))
                await self.close(code=4000) # 可以使用自定义代码表示认证超时
        except asyncio.CancelledError:
            # 任务被取消是正常的（意味着认证成功）
            pass
